package org.zjx.window.action;

import lombok.Getter;
import org.zjx.command.state.StateManager;
import org.zjx.window.window.ActivationManager;
import org.zjx.window.window.IWindow;

import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 动作命令抽象基类
 * 提供通用的执行框架，包括中断检查、重复执行防护和激活权管理
 *
 * @author zjx
 * @since 1.0
 */
@Getter
public abstract class Action implements IAction {

    /**
     * 状态管理器，用于访问和更新游戏状态
     */
    protected final StateManager stateManager;

    /**
     * 目标窗口，动作将在该窗口上执行
     */
    protected final IWindow targetWindow;

    /**
     * 动作名称，用于标识和日志记录
     */
    private final String actionName;

    /**
     * 是否需要激活窗口权限
     */
    private final boolean requiresActiveWindow;

    /**
     * 执行状态标记，防止在同一执行上下文中重复执行
     */
    private final AtomicBoolean executed = new AtomicBoolean(false);

    /**
     * 是否允许通过激活管理器重复执行
     */
    private final boolean allowReExecution;

    /**
     * 构造动作实例
     *
     * @param targetWindow 目标窗口，不能为null
     * @param requiresActiveWindow 是否需要激活窗口权限
     * @throws IllegalArgumentException 如果targetWindow为 null
     */
    public Action(IWindow targetWindow, boolean requiresActiveWindow) {
        this.targetWindow = Objects.requireNonNull(targetWindow, "目标窗口不能为 null");
        this.requiresActiveWindow = requiresActiveWindow;
        this.allowReExecution = requiresActiveWindow;
        this.actionName = this.getClass().getSimpleName();
        this.stateManager = targetWindow.getState();
    }

    /**
     * 构造动作实例（默认需要激活权限，不允许重复执行）
     *
     * @param targetWindow 目标窗口，不能为null
     * @throws IllegalArgumentException 如果targetWindow为 null
     */
    public Action(IWindow targetWindow) {
        this(targetWindow, false);
    }

    /**
     * 执行动作命令
     * 提供统一的执行框架，包括重复执行检查和激活权管理
     *
     * @return 执行是否成功
     * @throws InterruptedException 如果执行过程中线程被中断
     */
    @Override
    public final boolean execute() throws InterruptedException {
        return executeInternal(false);
    }

    /**
     * 通过激活管理器执行动作（允许重复执行）
     *
     * @return 执行是否成功
     * @throws InterruptedException 如果执行过程中线程被中断
     */
    public final boolean executeThroughActivation() throws InterruptedException {
        return executeInternal(true);
    }

    /**
     * 内部执行方法
     *
     * @param throughActivation 是否通过激活管理器执行
     * @return 执行是否成功
     * @throws InterruptedException 如果执行过程中线程被中断
     */
    private boolean executeInternal(boolean throughActivation) throws InterruptedException {
        // 检查中断状态
        checkInterruption();

        // 检查是否允许重复执行
        boolean shouldCheckExecution = !throughActivation || !allowReExecution;

        if (shouldCheckExecution && !executed.compareAndSet(false, true)) {
            System.err.println("动作已执行，跳过: " + actionName);
            return false;
        }

        boolean success = false;
        try {
            // 检查中断状态
            checkInterruption();

            // 如果需要激活权且窗口未激活，使用激活管理器
            if (requiresActiveWindow && !targetWindow.isActive()) {
                if (throughActivation) {
                    // 直接执行，避免循环调用
                    doExecute();
                    success = true;
                } else {
                    // 通过激活管理器执行
                    success = ActivationManager.executeWithActivation(this);
                }
            } else {
                // 直接执行动作
                doExecute();
                success = true;
            }

            return success;

        } catch (InterruptedException e) {
            // 恢复中断状态并重新抛出
            Thread.currentThread().interrupt();
            if (shouldCheckExecution) {
                executed.set(false); // 执行失败后重置状态
            }
            throw e;
        } catch (Exception e) {
            // 其他异常处理
            System.err.println("动作执行失败: " + actionName + " - " + e.getMessage());
            if (shouldCheckExecution) {
                executed.set(false); // 执行失败后重置状态
            }
            return false;
        }
    }

    /**
     * 检查线程中断状态
     * 如果线程被中断，抛出InterruptedException
     *
     * @throws InterruptedException 如果当前线程被中断
     */
    protected final void checkInterruption() throws InterruptedException {
        if (Thread.currentThread().isInterrupted()) {
            throw new InterruptedException("线程被中断，取消动作执行: " + actionName);
        }
    }

    /**
     * 检查是否被中断（非阻塞）
     *
     * @return 如果当前线程被中断返回true，否则返回false
     */
    protected final boolean isInterrupted() {
        return Thread.currentThread().isInterrupted();
    }

    /**
     * 重置执行状态
     * 允许动作重新执行
     */
    public final void reset() {
        executed.set(false);
    }

    /**
     * 检查是否已执行
     *
     * @return 如果动作已执行返回true，否则返回false
     */
    public final boolean isExecuted() {
        return executed.get();
    }

    /**
     * 具体的命令执行逻辑
     * 子类必须实现此方法来定义具体的业务逻辑
     *
     * @throws Exception 执行过程中可能抛出各种异常
     */
    protected abstract void doExecute() throws Exception;

    /**
     * 获取动作的字符串表示
     *
     * @return 包含动作名称和目标窗口的信息字符串
     */
    @Override
    public String toString() {
        return String.format("Action{name='%s', targetWindow='%s', requiresActive=%s, executed=%s, allowReExecution=%s}",
                actionName, targetWindow.getTitle(), requiresActiveWindow, executed.get(), allowReExecution);
    }
}